﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Internal.Util;
using NGuice.Inject.Binder;
using NGuice.Inject.Spi;
using NGuice.Inject.Matcher;
using System.Reflection;
using AopAlliance.Intercept;

namespace NGuice.Inject
{

    /// <summary>
    /// IModule模块接口的抽象支持实现，他减少大多数可读配置的重复编写。开发者应该继承
    /// 此接口并实现<seealso cref="AbstractModule.Configure()"/>方法，并在此方法中调用
    /// 在<see cref="Binder"/>中发现的方法（此抽象模块实现了大部分Binder方法，他将所有
    /// 绑定调用委托给内部的Binder绑定器）：
    /// <example>
    /// public class MyModule: AbstractModule {
    ///    protected void configure() {
    ///     Bind(typeof(Service).To(typeof(ServiceImpl)).In(typeof(Singleton));
    ///     Bind(typeof(CreditCardPaymentService));
    ///     Bind(typeof(PaymentService)).To(typeof(CreditCardPaymentService));
    ///     BindConstant().AnnotatedWith(Names.named("port")).To(8080);
    ///    }
    /// }
    /// </example>
    /// </summary>
    public abstract class AbstractModule : IModule
    {
        internal IBinder binder;

        public void Configure(IBinder builder)
        {
            lock (this)
            {
                Preconditions.CheckState(this.binder == null, "Re-entry is not allowed.");
                this.binder = Preconditions.CheckNotNull(builder, "builder");
                try
                {
                    Configure();
                }
                finally
                {
                    this.binder = null;
                }
            }
        }

        /// <summary>
        /// 子类应该实现的配置模板方法
        /// </summary>
        protected abstract void Configure();

        protected IBinder Binder
        {
            get
            {
                return binder;
            }
        }

        /// <seealso cref="Binder.BindScope<T>"/>
        protected virtual void BindScope<T>(IScope scope) where T : Attribute
        {
            binder.BindScope<T>(scope);
        }

        /// <seealso cref="Binder.Bind<T>"/>
        protected virtual ILinkedBindingBuilder<T> Bind<T>(Key<T> key)
        {
            return binder.Bind(key);
        }

        /// <seealso cref="Binder.Bind<T>"/>
        protected virtual IAnnotatedBindingBuilder<T> Bind<T>()
        {
            return binder.Bind<T>();
        }

        /// <seealso cref="Binder.BindConstant"/>
        protected virtual IAnnotatedConstantBindingBuilder BindConstant()
        {
            return binder.BindConstant();
        }

        /// <seealso cref="Binder.Install"/>
        protected virtual void Install(IModule module)
        {
            binder.Install(module);
        }

        /// <seealso cref="Binder.AddError"/>
        protected virtual void AddError(string message, params object[] arguments)
        {
            binder.AddError(message, arguments);
        }

        /// <seealso cref="Binder.AddError"/>
        protected virtual void AddError(Exception e)
        {
            binder.AddError(e);
        }

        /// <seealso cref="Binder.AddError"/>
        protected virtual void AddError(Message message)
        {
            binder.AddError(message);
        }

        /// <seealso cref="Binder.RequestInjection"/>
        protected virtual void RequestInjection(object instance)
        {
            binder.RequestInjectionForNoGeneric(instance);
        }

        /// <seealso cref="Binder.RequestStaticInjection"/>
        protected virtual void RequestStaticInjection(params Type[] types)
        {
            binder.RequestStaticInjection(types);
        }

        /*if[AOP]*/
        /// <summary>
        /// 绑定方法拦截器到匹配指定与指定方法上，一个方法将在以下情况下拦截：
        /// 1. NGuice创建的具有拦截的方法的实例
        /// 2. 类不能为sealed，方法为虚拟方法
        /// 3. protected、public、internal方法
        /// </summary>
        /// <param name="classMatcher">方法拦截器将被应用的类</param>
        /// <param name="methodMatcher">方法拦截器将被应用的方法</param>
        /// <param name="interceptors">拦截器</param>
        protected void BindInterceptor(IMatcher<Type> classMatcher, IMatcher<MethodInfo> methodMatcher, params IMethodInterceptor[] interceptors)
        {
            binder.BindInterceptor(classMatcher, methodMatcher, interceptors);
        }
        /*end[AOP]*/

        /// <summary>
        /// 从此模块添加一个依赖到key中，当注入器创建后，如果不能注入，NGuice将记录错误。
        /// 注意：这个需求可能适合隐式绑定，例如无参的默认构造器
        /// </summary>
        protected virtual void RequireBinding<T>(Key<T> key)
        {
            binder.GetProvider<T>(key);
        }

        /// <summary>
        /// 从此模块添加一个依赖到指定类型中，当注入器创建后，如果不能注入，NGuice将记录错误。
        /// 注意：这个需求可能适合隐式绑定，例如无参的默认构造器
        /// </summary>
        protected virtual void RequireBinding<T>()
        {
            binder.GetProvider<T>();
        }

        /// <seealso cref="Binder.GetProvider"/>
        protected virtual IProvider<T> GetProvider<T>(Key<T> key)
        {
            return binder.GetProvider<T>(key);
        }

        /// <seealso cref="Binder.GetProvider"/>
        protected virtual IProvider<T> GetProvider<T>()
        {
            return binder.GetProvider<T>();
        }

        /// <seealso cref="Binder.ConvertToTypes"/>
        protected virtual void ConvertToTypes<T>(IMatcher<T> typeMatcher, ITypeConverter converter)
        {
            binder.ConvertToTypes(typeMatcher, converter);
        }

        /// <seealso cref="Binder.CurrentStage"/>
        protected virtual Stage CurrentStage
        {
            get
            {
                return binder.CurrentStage;
            }
        }

        /// <seealso cref="Binder.GetMembersInjector"/>
        protected virtual IMembersInjector<T> GetMembersInjector<T>()
        {
            return binder.GetMembersInjector<T>();
        }


        /// <seealso cref="Binder.BindListener"/>
        protected virtual void BindListener<T>(IMatcher<T> typeMatcher, ITypeListener listener)
        {
            binder.BindListener(typeMatcher, listener);
        }

    }
}
